/*
	File:		AppearanceSampleMain.c

	Contains:	Main application code for our sample app.

	Version:	Appearance 1.0.2 SDK

	Copyright:	© 1997-98 by Apple Computer, Inc., all rights reserved.

	File Ownership:

		DRI:				Edward Voas

		Other Contact:		7 of 9, Borg Collective

		Technology:			OS Technologies Group

	Writers:

		(MAA)	Matt Ackeret
		(edv)	Ed Voas

	Change History (most recent first):
		 <5>     1/23/98	mxm		Added AutoSizeDialog for the About box
		 <4>	10/29/97	MAA		Put the font menu into a global so we can disable it when
									CDEFTester goes away.
		 <3>	10/28/97	MAA		Add Font menu back in, fix a bug in SetUpFontMenu
		 <2>	10/28/97	edv		Use RadioGroup control!
		 <1>	 9/11/97	edv		First checked in.
*/


//
//	This program is actually based on the skeleton code from Scott Knaster's
//	Macintosh Programming Secrets book. So, if you're looking at this code,
//	Scott, it may look slightly familiar.
//

#include <Types.h>
#include <Files.h>
#include <Gestalt.h>
#include <Processes.h>
#include <Movies.h>
#include <Menus.h>
#include <Fonts.h>
#include <DiskInit.h>
#include <Devices.h>
#include <TextUtils.h>
#include <Resources.h>
#include "Traps.h"
#include "TrapTools.h"
#include "Appearance.h"

#include "FinderWindow.h"
#include "DialogWindow.h"
#include "BevelDialog.h"
#include "BevelImageAPIWindow.h"
#include "CDEFTester.h"
#include "LiveFeedbackDialog.h"
#include "MegaDialog.h"
#include "UtilityWindow.h"
#include "SideUtilityWindow.h"
#include "MenuDrawing.h"

#define	MAXLONG		0X7FFFFFFF

/* ==================================================================================*/
/* ======================= R E S O U R C E   N U M B E R S ==========================*/
/* ==================================================================================*/

enum
{
	kAlertStartupError		= 129
};

enum
{
	kErrorStrings			= 128,
	kWeirdSystemString		= 1,
	kNoAppearanceString		= 2,
	kResourceMissingString	= 3
};

enum
{
	kAboutBoxDialogID		= 5000
};

#define kObjectWindowKind		2000

/* 	The following constants are used to identify menus and their items. The menu IDs
	have an "m" prefix and the item numbers within each menu have an "i" prefix. */

enum
{
	rMenuBar				= 128				/* application's menu bar */
};

enum
{
	mApple					= 128,				/* Apple menu */
	iAbout					= 1
};

enum
{
	mFile					= 129,				/* File menu */
	iClose					= 1,
	iQuit					= 3
};

enum
{
	kHorizZoomKind			= 128,
	kVertZoomKind			= 129
};

enum
{
	kMenuModifiers				= 145,
	kNoModifiersItem			= 1,
	kShiftModifierItem			= 2,
	kShiftOptionModifierItem	= 3,
	kShiftOptCntlModifierItem	= 4,
	kCommandDeleteItem			= 5,
	kIconSuiteItem				= 6
};

enum
{
	kAboutSampleCmd			= 'abou',
	kCloseCmd				= 'clos',
	kQuitCmd				= 'quit',
	kOpenFinderWindowCmd	= 'opfw',
	kOpenDialogWindowCmd	= 'opdw',
	kOpenBevelDialogCmd		= 'opbd',
	kNewFeaturesDialogCmd	= 'newf',
	kStandardAlertCmd		= 'stal',
	kBevelImageAPICmd		= 'bvli',
	kCDEFTesterCmd			= 'cdef',
	kLiveFeedbackCmd		= 'live',
	kUtilityWindowCmd		= 'util',
	kSideUtilityWindowCmd	= 'side',
	kMegaDialogCmd			= 'mega',
	kAutoSizeCmd			= 'asiz',
	kVerticalZoomCmd		= 'vert',
	kHorizontalZoomCmd		= 'horz'
};

enum
{
	kMenuDrawingTest		= 'mdra',
	kDumpHierarchy			= 'dhie'
};

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	Prototypes
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

static void		InitToolbox(void);
static void		MainEventLoop(void);

/* Event handling routines */

static void		HandleEvent(EventRecord *event);
static void		HandleActivate(EventRecord *event);
static void		HandleDiskInsert(EventRecord *event);
static void		HandleKeyPress(EventRecord *event);
static void 	HandleMouseDown(EventRecord *event);
static void		HandleOSEvent(EventRecord *event);
static void		HandleUpdate(EventRecord *event);

static void		AdjustMenus(void);
static void		HandleMenuCommand(long menuResult);

/* Utility routines */

static void		CloseAnyWindow(WindowPtr window);
static void		DeathAlert(short errorNumber);
static Boolean	IsAppWindow(WindowPtr window);
static Boolean 	IsDAWindow(WindowPtr window);
static Boolean	IsDialogWindow(WindowPtr window);

static Boolean	GetObjectFromWindow( WindowPtr window, BaseWindow** wind );
static void		SetUpFontMenu();
static void		SetUpModifiersMenu();
static void		DoAboutBox();

static void		AutoSizeDialogTest();
static void		SyncVertZoomRects( WindowPtr window );
static void		SyncHorizZoomRects( WindowPtr window );
static OSErr	GetReportFileSpec( FSSpecPtr file );

/* External routines */

extern void		TestStandardAlert();

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	Globals
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ


Boolean			gQuit;			/* 	We set this to TRUE when the user selects
									Quit from the File menu. Our main event loop
									exits gQuit is TRUE. */

Boolean			gInBackground;	/*	gInBackground is maintained by our osEvent
									handling routines. Any poart of the program
									can check it to find out if it is currently
									in the background. */

MenuHandle		gFontMenu = nil;		// Menu used to choose a font

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	Macros
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ

#define	HiWrd(aLong)	(((aLong) >> 16) & 0xFFFF)
#define	LoWrd(aLong)	((aLong) & 0xFFFF)

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯ main
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	Entry point for our program. We initialize the Toolbox, make sure we are
//	running on a sufficiently brawny machine, and put up the menu bar. Finally,
//	we start polling for events and handling then by entering our main event
//	loop.
//	
void main()
{
	/*	If you have stack requirements that differ from the default,
		then you could use SetApplLimit to increase StackSpace at
		this point, before calling MaxApplZone. */
		
	MaxApplZone();						/* 	Expand the heap so code segments load
											at the top */
	InitToolbox();						/*	Initialize the program */
	MainEventLoop();					/* 	Call the main event loop */
}

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯ InitToolbox
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	Set up the whole world, including global variables, Toolbox Managers, and
//	menus.
//	
static void
InitToolbox()
{
	Handle			menuBar;
	SInt32			result;
	OSErr			err;
	
	gInBackground = false;
	gQuit = false;
	
	InitGraf((Ptr) &qd.thePort);
	InitFonts();
	InitWindows();
	InitMenus();
	TEInit();
	InitDialogs(nil);
	InitCursor();
	
	if ( !TrapAvailable( _WaitNextEvent ) )
		DeathAlert( kWeirdSystemString );
	
	err = Gestalt( gestaltAppearanceAttr, &result );
	if ( err )
		DeathAlert( kNoAppearanceString );
		
	menuBar = GetNewMBar(rMenuBar);
	if ( menuBar == nil )
		DeathAlert( kResourceMissingString );
	
		//**************************************************************************//
		//	APPEARANCE ADOPTION ALERT!!												//
		//**************************************************************************//

		// In order to get the theme-savvy menu bar, we need to call
		// RegisterAppearanceClient.

	RegisterAppearanceClient();

	SetMenuBar(menuBar);
	
	DisposeHandle(menuBar);
	AppendResMenu(GetMenuHandle(mApple),'DRVR');
	
	SetUpFontMenu();

	SetUpModifiersMenu();
	
	AdjustMenus();

	DrawMenuBar();
		
	new MegaDialog();
}

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯ MainEventLoop
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	Get events and handle them by calling HandleEvent. On every event, we call
//	idle on the frontmost window, if there is one.
//	
static void
MainEventLoop()
{
	RgnHandle		cursorRgn;
	Boolean			gotEvent;
	EventRecord		event;
	WindowPtr		theWindow;
	BaseWindow*		window;
	
	cursorRgn = nil;
	while( !gQuit )
	{
		gotEvent = WaitNextEvent( everyEvent, &event, MAXLONG, cursorRgn );
		if ( gotEvent )
			HandleEvent( &event );
		
		theWindow = FrontWindow();
		if ( theWindow && GetObjectFromWindow( theWindow, &window ) )
		{
			window->Idle();			
		}
	}
}

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯ HandleEvent
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	Do the right thing for an event. Determine what kind of event it is and
//	call the appropriate routines.
//
static void
HandleEvent( EventRecord *event )
{
	switch ( event->what )
	{
		case mouseDown:
			HandleMouseDown( event );
			break;
			
		case keyDown:
		case autoKey:
			HandleKeyPress( event );
			break;
			
		case activateEvt:
			HandleActivate( event );
			break;
			
		case updateEvt:
			HandleUpdate( event );
			break;
			
		case diskEvt:
			HandleDiskInsert( event );
			break;
			
		case osEvt:
			HandleOSEvent( event );
	}
}

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯ HandleActivate
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	This is called when a window is activated or deactivated. In this sample,
//	the Window Manager's handling of activate and deactivate events is
//	sufficient. Others applications may have TextEdit records, controls, lists,
//	etc., to activate/deactivate.
//
static void
HandleActivate( EventRecord *event )
{
	WindowPtr		theWindow;
	Boolean			becomingActive;
	BaseWindow*		windObj;
	
	theWindow = (WindowPtr)event->message;
	becomingActive = (event->modifiers & activeFlag) != 0;

	if ( IsDialogWindow( theWindow ) )
	{
		DialogRef		dialog;
		SInt16			itemHit;

		DialogSelect( event, &dialog, &itemHit );
	}
	else if ( GetObjectFromWindow( theWindow, &windObj ) )
	{
		if ( becomingActive )
			windObj->Activate( *event );
		else
			windObj->Deactivate( *event );
	}
}

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯ HandleDiskInsert
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	Called when we get a disk-inserted event. Check the upper word of the
//	event message; if it's nonzero, then a bad disk was inserted, and it
//	needs to be formatted.
//	
static void
HandleDiskInsert( EventRecord *event )
{
	Point		aPoint = {100, 100};
	
	if ( HiWrd( event->message ) != noErr )
	{
		DIBadMount( aPoint, event->message );
	}
}

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯ HandleKeyPress
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	The user pressed a key, what are you going to do about it?
//
static void
HandleKeyPress( EventRecord *event )
{
	char		key;
	
	key = event->message & charCodeMask;
	if ( event->modifiers & cmdKey )
	{
		AdjustMenus();

		//**************************************************************************//
		//	APPEARANCE ADOPTION ALERT!!												//
		//**************************************************************************//
		// Here we use the new MenuEvent routine instead of menu key. This allows
		// us to handle extended modifier keys for the menu items that use them.
		
		HandleMenuCommand( MenuEvent( event ) );
	}
	else
	{
		WindowPtr 	window = FrontWindow();
		BaseWindow*	object;
		
		if ( GetObjectFromWindow( window, &object ) )
		{
			object->HandleKeyDown( *event );
		}
	}
}

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯ HandleMouseDown
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	Called to handle mouse clicks. The user could have clicked anywhere,so
//	let's first find out where by calling FindWindow. That returns a number
//	indicating where in the screen the mouse was clicked. "switch" on that
//	number and call the appropriate routine.
//
static void
HandleMouseDown( EventRecord *event )
{
	long		newSize;
	Rect		growRect;
	WindowPtr	theWindow;
	short		part;
	
	part = FindWindow( event->where, &theWindow );
	
	switch ( part )
	{
		case inMenuBar:
			AdjustMenus();
			HandleMenuCommand( MenuSelect( event->where ) );
			break;
			
		case inSysWindow:
			SystemClick( event, theWindow );
			break;
			
		case inContent:
			if ( theWindow != FrontWindow() )
			{
				SelectWindow( theWindow );
			}
			else
			{
				BaseWindow* 	wind;
				
				if ( GetObjectFromWindow( theWindow, &wind ) )
					wind->HandleClick( *event );
			}
			break;
			
		case inDrag:
			DragWindow( theWindow, event->where, &qd.screenBits.bounds );
			if ( ((WindowPeek)theWindow)->windowKind == kHorizZoomKind )
				SyncHorizZoomRects( theWindow );
			else if ( ((WindowPeek)theWindow)->windowKind == kVertZoomKind )
				SyncVertZoomRects( theWindow );
			break;
			
		case inGrow:
			growRect = qd.screenBits.bounds;
			growRect.top = growRect.left = 80;
			newSize = GrowWindow(theWindow,event->where,&growRect);
			if (newSize != 0)
			{
				BaseWindow*		wind;
				
				if ( GetObjectFromWindow( theWindow, &wind ) )
					wind->Resize( LoWrd(newSize), HiWrd(newSize) );
				else
					SizeWindow( theWindow, LoWrd( newSize ), HiWrd( newSize ), true );
			}
			break;
			
		case inGoAway:
			if (TrackGoAway(theWindow,event->where))
				CloseAnyWindow(theWindow);
			break;
			
		case inZoomIn:
		case inZoomOut:
			if ( TrackBox( theWindow, event->where, part ) )
			{
				SetPort( theWindow );
				EraseRect( &theWindow->portRect );
				ZoomWindow( theWindow, part, true );
				InvalRect( &theWindow->portRect );
			}
			break;
	}
}

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯ HandleOSEvent
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	Deal with OSEvents. These are messages that the process manager sends to
//	us. Here, we deal with the suspend and resume message.
//	
static void
HandleOSEvent( EventRecord *event )
{
	switch( (event->message >> 24) & 0x00FF )
	{
		case suspendResumeMessage:
		
				// In our SIZE resource, we say that we are MultiFinder aware.
				// This means that we take on the responsibility of activating
				// and deactivating our own windows on suspend/resume events. */

			gInBackground = (event->message & resumeFlag) == 0;

			WindowPtr		window = FrontWindow();
		
			if ( window )
			{
				BaseWindow*		wind;
				
				if ( GetObjectFromWindow( window, &wind ) )
				{
					if ( gInBackground )
						wind->Deactivate( *event );
					else
						wind->Activate( *event );
				}
			}
			break;
			
		case mouseMovedMessage:
			break;
	}
}

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯ HandleUpdate
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	This is called when an update event is received for a window. It calls
//	DoUpdateWindow to draw the contents of an application window. As an
//	efficiency measure that does not have to be followed, it calls the drawing
//	routine only if the visRgn is nonempty. This will handle situations where
//	calculations for drawing or drawing itself is very time consuming.
//	
static void
HandleUpdate( EventRecord *event )
{
	 WindowPtr			theWindow = (WindowPtr)event->message;
	 BaseWindow*		wind;
	 
	if ( IsDialogWindow( theWindow ) )
	{
		DialogRef		dialog;
		SInt16			itemHit;

		DialogSelect( event, &dialog, &itemHit );
	}
	else if ( GetObjectFromWindow( theWindow, &wind ) )
	{
	 	if ( !EmptyRgn( theWindow->visRgn ) )
	 	{
	 		SetPort( theWindow );
	 		wind->Update( *event );
	 	}
	}
	else
	{
		BeginUpdate( theWindow );
		EndUpdate( theWindow );
	}
}

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯ AdjustMenus
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	Enable and disable menus based on the currene state. The user can only 
//	select enabled menu items. We set up all the menu items before calling
//	MenuSelect or MenuKey, since these are the only times that a menu item can
//	be selected. Note that MenuSelect is also the only time the user will see
//	menu items. This approach to deciding what enable/disable state a menu
//	item has has the advantage of concentrating all the decision making in one
//	routine, as opposed to being spread throughout the application. Other
//	application designs may take a different approach that is just as valid.
//	
static void
AdjustMenus()
{
	WindowPtr		theWindow;
	MenuHandle		menu;
	BaseWindow*		wind;
	
	theWindow = FrontWindow();
	
	menu = GetMenuHandle( mFile );
	
	if ( theWindow )
		EnableItem( menu, iClose );
	else
		DisableItem( menu, iClose );

	if ( GetObjectFromWindow( theWindow, &wind ) )
	{
		wind->AdjustMenus();
	}
}

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯ HandleMenuCommand
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	This is called when an item is chosen from the menu bar (after calling
//	MenuSelect or MenuKey). It performs the right operation for each command.
//	It tries to get the command ID of the menu item selected. If it can't, or
//	the command is unknown, we pass it on to the front window, if any. We
//	also special case the Apple menu items.
//	
static void
HandleMenuCommand( long menuResult )
{
	short		menuID;
	short		menuItem;
	Str255		daName;
	UInt32		command;
	Boolean		handled;
	OSErr		err;
	WindowPtr	window;
	
	menuID = HiWrd( menuResult );
	menuItem = LoWrd( menuResult );
	
	err = GetMenuItemCommandID( GetMenuHandle( menuID ), menuItem, &command );
	
	handled = false;
	
	if ( err || command == 0 )
	{
		if ( menuID == mApple )
		{
			GetMenuItemText( GetMenuHandle( mApple ), menuItem, daName );
			OpenDeskAcc( daName );
			handled = true;
		}
	}
	else
	{
		handled = true;
		
		switch( command )
		{
			case kAboutSampleCmd:
				DoAboutBox();
				break;
			
			case kCloseCmd:
				if ( FrontWindow() )
					CloseAnyWindow( FrontWindow() );
				break;
			
			case kQuitCmd:
				gQuit = true;
				break;

			case kOpenFinderWindowCmd:
				new FinderWindow();
				break;
				
			case kOpenDialogWindowCmd:
				new DialogWindow();
				break;
			
			case kOpenBevelDialogCmd:
				new BevelDialog();
				break;
			
			case kBevelImageAPICmd:
				new BevelImageAPIWindow();
				break;
				
			case kCDEFTesterCmd:
				new CDEFTester();
				break;
			
			case kStandardAlertCmd:
				TestStandardAlert();
				break;
			
			case kLiveFeedbackCmd:
				new LiveFeedbackDialog();
				break;
			
			case kUtilityWindowCmd:
				new UtilityWindow();
				break;
			
			case kSideUtilityWindowCmd:
				new SideUtilityWindow();
				break;
			
			case kMegaDialogCmd:
				new MegaDialog();
				break;
			
			case kAutoSizeCmd:
				AutoSizeDialogTest();
				break;
			
			case kVerticalZoomCmd:
				window = GetNewWindow( 133, nil, (WindowPtr)-1L );
				if ( window )
				{
					((WindowPeek)window)->windowKind = kVertZoomKind;
					SetWindowPic( window, GetPicture( 133 ) );
					SyncVertZoomRects( window );
				}
				break;
			
			case kHorizontalZoomCmd:
				window = GetNewWindow( 134, nil, (WindowPtr)-1L );
				if ( window )
				{
					((WindowPeek)window)->windowKind = kHorizZoomKind;
					SetWindowPic( window, GetPicture( 134 ) );
					SyncHorizZoomRects( window );
				}
				break;
			
			case kMenuDrawingTest:
				DrawMenuStuff();
				break;
			
			case kDumpHierarchy:
				if ( FrontWindow() )
				{
					FSSpec		file;
					
					GetReportFileSpec( &file );
					DumpControlHierarchy( FrontWindow(), &file );
				}
				break;
			
			default:
				handled = false;
				break;
					
		}
	}
	
	if ( !handled )
	{
		WindowPtr 	frontWindow = FrontWindow();
		BaseWindow* wind;
		
		if ( frontWindow )
		{
			if ( GetObjectFromWindow( frontWindow, &wind ) )
			{
				wind->HandleMenuSelection( menuID, menuItem );
			}
		}
	}

	HiliteMenu(0);
}

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯ CloseAnyWindow
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	Close the given window in a manner appropriate for that window. If the
//	window belongs to a DA, we call CloseDeakAcc. For dialogs, we simply hide
//	the window. If we had any document windows, we would probably call either
//	DisposeWindow or CloseWindow after disposing of any document data and/or
//	controls.
//	
static void
CloseAnyWindow( WindowPtr window )
{
	BaseWindow*		wind;
	
	if ( IsDAWindow( window ) )
	{
		CloseDeskAcc( ((WindowPeek)window)->windowKind );
	}
	else if ( GetObjectFromWindow( window, &wind ) )
	{
		delete wind;
	}
	else
		DisposeWindow( window );
}

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯ DeathAlert
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	Display an alert that tell the user an err occurred, then exit the
//	program. This routine is used as an ultimate bail-out for serious errors
//	that prohibit the continuation of the application. The error number is
//	used to index an 'STR#' resource so that a relevant message can be
//	displayed.
//
static void
DeathAlert( short errNumber )
{
	short			itemHit;
	Str255			theMessage;
	
	SetCursor( &qd.arrow );
	GetIndString( theMessage, kErrorStrings, errNumber );
	ParamText( theMessage, nil, nil, nil );
	itemHit = StopAlert( kAlertStartupError, nil );
	ExitToShell();
}

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯ IsAppWindow
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	Check to see if a window belongs to the application. If the window
//	pointer passed was NIL, then it could not be an application window.
//	WindowKinds that are negative belong to the system and windowKinds
//	less that userKind are reserved by Apple except for userKinds equal to
//	dialogKind, which means it's a dialog.
//	

static Boolean
IsAppWindow( WindowPtr window )
{
	short		windowKind;
	
	if ( window == nil )
		return false;
		
	windowKind = ((WindowPeek)window)->windowKind;
	return( (windowKind >= userKind) || (windowKind == dialogKind) );
}

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯ IsDAWindow
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	Check to see if a window belongs to a desk accessory. It belongs to a DA
//	if the windowKind field of the window record is negative.
//	
static Boolean
IsDAWindow( WindowPtr window )
{
	if ( window == nil )
		return false;

	return( ((WindowPeek)window)->windowKind < 0 );
}

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯ IsDialogWindow
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	Check to see if a window is a dialog window. We can determine this by
//	checking to see if the windowKind field is equal to dialogKind.
//
static Boolean
IsDialogWindow( WindowPtr window )
{
	if ( window == nil )
		return false;

	return( ((WindowPeek)window)->windowKind == dialogKind );
}

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯ GetObjectFromWindow
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	Gets the object pointer from the refCon of the given window if the kind
//	is right. If the kind is wrong, or the refCon is null, we return false.
//
static Boolean
GetObjectFromWindow( WindowPtr window, BaseWindow** wind )
{
	SInt32		test;
	
	if ( ((WindowPeek)window)->windowKind != kObjectWindowKind )
		return false;
		
	test = GetWRefCon( window );
	if ( test == nil ) return false;
	
	*wind = (BaseWindow*)test;

	return true;
}

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯ SetUpFontMenu
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	This routine calls AddResMenu to add all fonts to our font menu. We then
//	go thru each item and set the item's font to the actual font!
//
static void
SetUpFontMenu()
{
	SInt16			i, numItems;
	Str255			fontName;
	SInt16			fontNum;
	
	gFontMenu = GetMenu( kMenuFonts );
	if ( gFontMenu == nil ) return;
	
	AppendResMenu( gFontMenu, 'FONT' );
	
	numItems = CountMItems( gFontMenu );
	for ( i = 1; i <= numItems; i++ )
	{
		GetMenuItemText( gFontMenu, i, fontName );
		GetFNum( fontName, &fontNum );
		SetMenuItemFontID( gFontMenu, i, fontNum );
	}	
	InsertMenu(gFontMenu,0);
	DisableItem(gFontMenu,0);
}

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯ SetUpModifiersMenu
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	This routine programmatically sets the modifiers for our modifier menu.
//
static void
SetUpModifiersMenu()
{
	MenuHandle		menu;
	Handle			suite;
	OSErr			err;
	
	menu = GetMenuHandle( kMenuModifiers );
	if ( menu == nil ) return;

	SetMenuItemModifiers( menu, kShiftModifierItem, kMenuShiftModifier );	
	SetMenuItemModifiers( menu, kShiftOptionModifierItem, kMenuShiftModifier + kMenuOptionModifier );	
	SetMenuItemModifiers( menu, kShiftOptCntlModifierItem, kMenuShiftModifier + kMenuOptionModifier + kMenuControlModifier );	

	SetItemCmd( menu, kCommandDeleteItem, 0x08 ); // delete key
	SetMenuItemKeyGlyph( menu, kCommandDeleteItem, 0x0A ); // delete key glyph in font
	
	err = GetIconSuite( &suite, -3997, kSelectorAllAvailableData );
	if ( err == noErr )
		SetMenuItemIconHandle( menu, kIconSuiteItem, kMenuIconSuiteType, suite );
}

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯ DoAboutBox
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	Puts up our about box dialog. Note that we use a dialog and NOT an alert.
//	This is a good practice to get into, since alerts are now colored differently
//	to distiguish them from normal dialogs.
//
static void
DoAboutBox()
{
	DialogPtr		dialog;
	SInt16			itemHit;
	
	dialog = GetNewDialog( kAboutBoxDialogID, nil, (WindowPtr)-1L );
	if ( dialog == nil ) return;

	AutoSizeDialog(dialog); 
	SetDialogDefaultItem( dialog, 4 );	
	ModalDialog( nil, &itemHit );
	
	DisposeDialog( dialog );
}

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯ AutoSizeDialogTest
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	Simple little routine to demonstrate the AutoSizeDialog API
//
static void
AutoSizeDialogTest()
{
	DialogPtr		dialog;
	SInt16			itemHit = 0;
	
	dialog = GetNewDialog( 4000, nil, (WindowPtr)-1L );
	if ( dialog == nil ) return;
	
	SetDialogDefaultItem( dialog, 2 );
	
	while ( itemHit != 2 )
	{
		ModalDialog( nil, &itemHit );
		
		if ( itemHit == 3 )
			AutoSizeDialog( dialog );
	}
	DisposeDialog( dialog );
}

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯ SyncVertZoomRects
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	Sets up the standard and user rectangles for our vertical zooming window.
//
static void
SyncVertZoomRects( WindowPtr window )
{
	Rect		bounds;
	
	SetPort( window );
	bounds = window->portRect;
	
	if ( (bounds.bottom - bounds.top) < 200 )
		bounds.bottom = bounds.top + 200;
		
	LocalToGlobal( &topLeft( bounds ) );
	LocalToGlobal( &botRight( bounds ) );
	
	SetWindowStandardState( window, &bounds );
	
	bounds.bottom = bounds.top + 60;
	SetWindowUserState( window, &bounds );
}

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯ SyncHorizZoomRects
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	Sets up the standard and user rectangles for our horizontal zooming window.
//
static void
SyncHorizZoomRects( WindowPtr window )
{
	Rect		bounds;
	
	SetPort( window );
	bounds = window->portRect;

	if ( (bounds.right - bounds.left) < 240 )
		bounds.right = bounds.left + 240;
		
	LocalToGlobal( &topLeft( bounds ) );
	LocalToGlobal( &botRight( bounds ) );
	
	SetWindowStandardState( window, &bounds );
	
	bounds.right = bounds.left + 60;
	SetWindowUserState( window, &bounds );
}

//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	₯ GetReportFileSpec
//ΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡΡ
//	Returns our file spec for dumping pane information.
//
static OSErr
GetReportFileSpec( FSSpecPtr file )
{
	FCBPBRec	pb;
	Str255		ourName;
	OSErr		err;
	
	pb.ioVRefNum	= -1;
	pb.ioFCBIndx	= 0;
	pb.ioNamePtr	= ourName;
	pb.ioRefNum		= CurResFile();
	
	err = PBGetFCBInfoSync( &pb );
	if ( err ) return err;
	
	err = FSMakeFSSpec( pb.ioFCBVRefNum, pb.ioFCBParID, "\pPane Dump", file );
	return err;
}
